/*
```C#
/*
 * 版权所有 (c) 2019 Made With Monster Love (Pty) Ltd
 * 
 * 特此免费授予任何获得本软件及相关文档文件（以下简称“软件”）副本的人，无限制地处理软件，包括但不限于使用、复制、修改、合并、出版、分发、再许可和/或出售软件副本的权利，并允许软件接受者这样做，但须符合以下条件：
 * 
 * 上面的版权声明和许可通知应包含在本软件的所有副本或主要部分中。
 * 
 * 软件按“原样”提供，不提供任何形式的明示或暗示保证，包括但不限于对适销性、特定用途的适用性和非侵权的保证。在任何情况下，作者或版权持有人均不对任何索赔、损害或其他责任承担责任，无论是在合同诉讼、侵权诉讼或其他诉讼中，还是源于、源于或与软件或软件的使用或其他交易有关。
 */

using System;
using System.Collections.Generic;

// 警告！
// 这是某种脆弱的事件模式实现。建议不要在状态机之外使用它们
// 
namespace MonsterLove.StateMachine
{
    public class StateEvent
    {
        //根据状态获取int
        private Func<int> getStateInt;
        private Func<bool> isInvokeAllowed;
        private Action[] routingTable;

        public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
        {
            this.isInvokeAllowed = isInvokeAllowed;
            this.getStateInt = stateProvider;
            routingTable = new Action[capacity];
        }
        
        internal void AddListener(int stateInt, Action listener)
        {
            routingTable[stateInt] = listener;
        }

        public void Invoke()
        {
            if (isInvokeAllowed != null && !isInvokeAllowed())
            {
                return;
            }

            Action call = routingTable[getStateInt()];
            if (call != null)
            {
                call();
                return;
            }
        }
    }
    
    public class StateEvent<T>
    {
        private Func<int> getStateInt;
        private Func<bool> isInvokeAllowed;
        private Action<T>[] routingTable;
        
        public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
        {
            this.isInvokeAllowed = isInvokeAllowed;
            this.getStateInt = stateProvider;
            routingTable = new Action<T>[capacity];
        }

        internal void AddListener(int stateInt, Action<T> listener)
        {
            routingTable[stateInt] = listener;
        }

        public void Invoke(T param)
        {
            if (isInvokeAllowed != null && !isInvokeAllowed())
            {
                return;
            }

            Action<T> call = routingTable[getStateInt()];
            if (call != null)
            {
                call(param);
                return;
            }
        }
    }
    
    public class StateEvent<T1, T2>
    {
        private Func<int> getStateInt;
        private Func<bool> isInvokeAllowed;
        private Action<T1,T2>[] routingTable;
        
        public StateEvent(Func<bool> isInvokeAllowed, Func<int> stateProvider, int capacity)
        {
            this.isInvokeAllowed = isInvokeAllowed;
            this.getStateInt = stateProvider;
            routingTable = new Action<T1, T2>[capacity];
        }

        internal void AddListener(int stateInt, Action<T1, T2> listener)
        {
            routingTable[stateInt] = listener;
        }

        public void Invoke(T1 param1, T2 param2)
        {
            if (isInvokeAllowed != null && !isInvokeAllowed())
            {
                return;
            }
            
            Action<T1, T2> call = routingTable[getStateInt()];
            if (call != null)
            {
                call(param1, param2);
                return;
            }
        }
    }
}